home *** CD-ROM | disk | FTP | other *** search
/ Gigarom 1 / Gigarom Macintosh Archives (Quantum Leap)(CDRM1080320)(1993).iso / FILES / DEV / C-H / CHexDmpDA.cpt / Hex Dump DA / main.HexDumpDA.c < prev    next >
C/C++ Source or Header  |  1988-06-15  |  10KB  |  462 lines

  1.  
  2. /* 
  3.  *    main.HexDumpDA.c
  4.  *
  5.  *    HexDump is a DA that displays the contents of a file in hex and ASCII,
  6.  *    intended as an example of how to write a desk accessory.  Among other 
  7.  *    things, it shows the structure of a DA, how a DA gets and responds to 
  8.  *    events, and how a DA manages the menu bar.
  9.  *    
  10.  *    Steve Stein, Symantec Corp.
  11.  *
  12.  */
  13.  
  14. #include <DeviceMgr.h>
  15. #include <WindowMgr.h>
  16. #include <MenuMgr.h>
  17. #include <EventMgr.h>
  18. #include <FileMgr.h>
  19. #include <ToolboxUtil.h>
  20. #include <StdFilePkg.h>
  21. #include <pascal.h>
  22.  
  23. #include "HexDump.h"
  24.  
  25. /*  global variables  */
  26.  
  27. int             already_open = 0;    /*  1 -> DA is already open      */
  28. DCtlPtr         dce;                /*  device control entry          */
  29. MenuHandle         menu = 0L;            /*  handle for our menu         */
  30. int                menuID;                /*    our menu ID                    */
  31. WindowPtr         wp = 0L;            /*    our window pointer             */
  32. Cursor            wait;                /*     a copy of the watch cursor    */
  33.  
  34. extern int        fileRef;            /*  the refnum of the file we're showing */
  35. extern long        fileSize;            /*    and the file's size (in bytes)         */
  36. enum fork        whichFork;            /*    which fork are we viewing?    */
  37.  
  38. extern    Handle     findBufH;
  39.  
  40. /*
  41.  *  main program
  42.  *
  43.  *  The first two arguments are the values passed in registers A0/A1
  44.  *  to an assembly-language desk accessory.  The third argument is a
  45.  *  selector indicating which entry point was called.
  46.  *
  47.  *  No assembly language is needed to write a desk accessory in
  48.  *  LightspeedC!
  49.  *
  50.  */
  51.  
  52. main(p, d, n)
  53. cntrlParam *p;    /*  ==> parameter block  */
  54. DCtlPtr d;        /*  ==> device control entry  */
  55. int n;            /*  entry point selector  */
  56. {
  57.     /*  if dCtlStorage is nil then our storage wasn't allocated...            */
  58.     
  59.     if (d->dCtlStorage == 0) {                    /*  we must abort            */
  60.         if (n == 0) {                            /*  if request is "open"    */
  61.             SysBeep(3);                            /*    beep, then close the DA */
  62.             CloseDriver(d->dCtlRefNum);
  63.         }
  64.         return(0);                                /*     goodbye */
  65.     }
  66.     
  67.     dce = d;                            /* copy the DCE ptr into our globals */
  68.     dce->dCtlFlags &= ~dCtlEnable;        /* we are not re-entrant             */
  69.  
  70.     switch (n) {                                /*  handle request: */
  71.         case 0:                                    /*      open        */
  72.             doOpen();                           
  73.             break;    
  74.         case 2:                                    /*      control     */
  75.             doControl(p->csCode, p->csParam); 
  76.             break;    
  77.         case 4:                                    /*      close       */
  78.             doClose();
  79.             break;    
  80.         default: ;
  81.     }
  82.     
  83.     dce->dCtlFlags |= dCtlEnable;    /* enable control calls once more */
  84.     return(0);                        /* we are done  */
  85. }
  86.  
  87. /*
  88.  *  doOpen - initialize DA
  89.  *
  90.  *  This routine is called each time the DA is selected from the Apple
  91.  *  menu, even if it is already open.  We need to make sure to go
  92.  *  through our initialization the first time only, so we use a (global)
  93.  *    flag "already_open" to keep track.
  94.  *  
  95.  *  However, the Device Manager resets the "dCtlFlags", "dCtlMenu",
  96.  *  "dCtlDelay", and "dCtlEMask" fields of the device control entry
  97.  *  from the corresponding fields of the device header each time the
  98.  *  desk accessory is opened, EVEN IF IT ALREADY OPEN.  Therefore we
  99.  *  must set these fields to their proper values each time.
  100.  *
  101.  *    We have to set the dNeedGoodBye flag so that we can close the file 
  102.  *    we're viewing if the application quits out from under us.
  103.  */
  104.  
  105. doOpen()
  106. {
  107.  
  108.         /*  every time ...  */
  109.     
  110.     dce->dCtlFlags |= dNeedLock|dNeedGoodBye;
  111.     if (wp) 
  112.         SelectWindow(wp);            /* bring our window front */
  113.     if (already_open) {
  114.         dce->dCtlMenu = menuID;        /* set the menu id */
  115.         return;
  116.     }
  117.         
  118.         /*  first time only ...  */
  119.         /*        do some global initialization */
  120.         /*      Create our menu        */
  121.         /*      Create our window     */
  122.         /*      Open a file         */
  123.         
  124.     Get_Wait_Cursor();
  125.     already_open = 1;
  126.  
  127.     Create_Menu();
  128.     Create_Window();
  129.  
  130.     HiliteMenu( dce->dCtlMenu );    /* to simulate "open" menu selection */
  131.     if (!doOpenFile()) {            /* if user cancels, close HexDump */
  132.         CloseDriver(dce->dCtlRefNum);                       /*  Quit  */
  133.         return;
  134.     };
  135.     HiliteMenu(0);
  136.  
  137.     if (!Init_Find())                 /* Init_Find will fail if there's not */
  138.                                     /* enough memory for the find buffer  */
  139.         Disable_Find();
  140. }
  141.  
  142. /* 
  143.  *    doControl - handle DA actions
  144.  *
  145.  *  This routine handles the DA actions that may be required.  This
  146.  *    DA must respond to two control actions: menu selections and events.
  147.  *    In addition, this routine can also handle the "goodbye kiss" when
  148.  *  the application quits out from under the DA.
  149.  *
  150.  */
  151.  
  152. doControl(code, parm)
  153. int code;
  154. int *parm;
  155. {
  156.     switch (code) {
  157.         case accMenu:  
  158.             doMenu(parm[1]);
  159.             break;
  160.         case accEvent: 
  161.             doEvent(*((EventRecord **)parm));
  162.             break;
  163.         case goodBye:  
  164.             doGoodBye();
  165.             break;
  166.         default: ;
  167.     }
  168.     if (code != accCursor) Update_Menu_Bar();
  169. }
  170.  
  171. /*
  172.  *  doClose - clean up before being closed
  173.  *
  174.  */
  175.  
  176. doClose()
  177. {
  178.     Close_File( fileRef );
  179.     DisposHandle( findBufH );
  180.     DeleteMenu(dce->dCtlMenu);
  181.     DrawMenuBar();
  182.     dce->dCtlMenu = 0;
  183.     DisposeMenu(menu);
  184.     Destroy_Window();
  185. }
  186.  
  187. /* Menu maintenance routines: */
  188.  
  189. /*     
  190.  *    Create_Menu
  191.  *
  192.  *    Get our menu from the resource file, set dce->dCtlMenu,
  193.  *    insert the menu into the menu bar and draw the menu bar.
  194.  */
  195.  
  196. static
  197. Create_Menu()
  198. {
  199.     dce->dCtlMenu = menuID = OwnedResourceID( MENUID );
  200.     menu = GetMenu(menuID);
  201.     (**menu).menuID = menuID;
  202.     InsertMenu(menu = GetMenu(menuID), 0);
  203.     DrawMenuBar();
  204. }
  205.  
  206. /* 
  207.  *    Update_Menu_Bar -    Manage the appearance of our menu in the menu bar
  208.  *
  209.  *     Our menu should appear when the front window belongs to us.
  210.  */
  211.  
  212. static
  213. Update_Menu_Bar()
  214. {
  215.     register WindowPeek wPtr = (WindowPeek) FrontWindow ();
  216.  
  217.     if (wPtr) {        /* there should always be a window, but we'll check. */
  218.         if ( wPtr->windowKind == dce->dCtlRefNum ) {
  219.             if (!GetMHandle (dce->dCtlMenu)) {
  220.                 InsertMenu (menu, 0);
  221.                 DrawMenuBar ();
  222.             }
  223.         }
  224.         else if (GetMHandle (dce->dCtlMenu)) {
  225.                 DeleteMenu (dce->dCtlMenu);
  226.                 DrawMenuBar ();
  227.         }
  228.     }
  229. }
  230.  
  231. static
  232. Disable_Find()
  233. {
  234.     /* we had no memory for the find buffer */
  235.     DisableItem(menu, FIND);
  236.     DisableItem(menu, FINDAGAIN);
  237. }
  238.  
  239. static
  240. Set_Fork(option)
  241. enum fork option;
  242. {
  243.     whichFork = option;
  244.     if (option==data) {
  245.         CheckItem( menu, DATAFORK, true );
  246.         CheckItem( menu, RSRCFORK, false );
  247.     }
  248.     else {
  249.         CheckItem( menu, DATAFORK, false );
  250.         CheckItem( menu, RSRCFORK, true );
  251.     }
  252. }
  253.  
  254. /*
  255.  *  doMenu - process menu selection
  256.  *
  257.  */
  258.  
  259. doMenu(i)    /*  the i-th menu item was selected  */
  260. int i;
  261. {    
  262.     switch (i) {
  263.         case ABOUT:        doAbout();                break;
  264.         case OPEN:        doOpenFile();             break;
  265.         case DUMPTO:    doDumpTo();                break;
  266.         case DATAFORK:    doOpenFork( data );     break;
  267.         case RSRCFORK:    doOpenFork( resource ); break;
  268.         case FIND:        doFind();                break;
  269.         case FINDAGAIN:    doFindAgain();            break;
  270.         case GOTO:        doGoto();                break;
  271.         case QUIT:
  272.             CloseDriver(dce->dCtlRefNum);    /* close down the DA */
  273.             return;
  274.     }
  275.     HiliteMenu(0);
  276. }
  277.  
  278. static
  279. doOpenFork( f )
  280. enum fork f;
  281. {
  282.     int newFileRef;
  283.     
  284.     if (f!=whichFork) {
  285.         if (Open_Fork(f, &newFileRef)) {
  286.             New_Open_File( newFileRef );
  287.             Set_Fork(f);
  288.         }
  289.         else
  290.             ErrorStr("\pCan't open fork.");
  291.     }
  292. }
  293.  
  294. static
  295. doOpenFile()
  296. {
  297.     char        *fileName;
  298.     int            vRef;
  299.     enum fork    option;
  300.     int            newFileRef;
  301.     
  302.     do {
  303.         if (!oldfilename(&option )) 
  304.             return 0;
  305.     } while (!Open_Fork(option, &newFileRef));
  306.     New_Open_File( newFileRef );
  307.     Set_Fork(option);
  308.     return 1;
  309. }
  310.  
  311. /*
  312.  *    TestWindowRgn uses the window's WDEF proc to sort out mouse hits.
  313.  *    In an application, FindWindow does this for you.  In a DA, you
  314.  *    must do it yourself.
  315.  */
  316.  
  317. static
  318. Boolean TestWindowRgn(wp,p,msg)
  319. WindowPtr wp;
  320. Point p;
  321. int msg;
  322. {
  323.     ProcPtr wDef;
  324.     
  325.     wDef = (ProcPtr) *((WindowPeek)wp) -> windowDefProc;
  326.     return(CallPascalL( 8, wp, (int) wHit, p, wDef )==msg);
  327. }
  328.  
  329. doMouse(p)
  330. Point p;
  331. {
  332.     if (TestWindowRgn(wp, p, wInGrow))
  333.         doGrow(p);
  334.     else if (TestWindowRgn(wp, p, wInZoomIn))
  335.         doZoom(p, inZoomIn);
  336.     else if (TestWindowRgn(wp, p, wInZoomOut))
  337.         doZoom(p, inZoomOut);
  338.     else 
  339.         doScrollControl(p);
  340. }
  341.  
  342. doCmdKey(c)
  343. char c;
  344. {
  345.     int code;
  346.     switch (c) {
  347.         case 'o':
  348.         case 'O': code = OPEN;         break;
  349.         case 'd':
  350.         case 'D': code = DUMPTO;     break;
  351.         case 'f':
  352.         case 'F': code = FIND;         break;
  353.         case 'a':
  354.         case 'A': code = FINDAGAIN; break;
  355.         case 'g':
  356.         case 'G': code = GOTO;         break;
  357.         case 'q':
  358.         case 'Q': code = QUIT;         break;
  359.         default : SysBeep(10);         return;
  360.     }
  361.     HiliteMenu( dce->dCtlMenu );
  362.     doMenu( code );
  363. }
  364.  
  365. /*
  366.  *    doEvent is the DA's event handler.
  367.  */
  368.  
  369. doEvent(e)
  370. EventRecord *e;
  371. {
  372.     switch (e->what) {
  373.         case updateEvt: 
  374.             doUpdate();    
  375.             break;
  376.         case mouseDown:    
  377.             doMouse(e->where);
  378.             break;
  379.         case activateEvt: 
  380.             doActivate((Boolean)(e->modifiers & activeFlag));
  381.             break;
  382.         case keyDown: 
  383.         case autoKey:
  384.             if ( e->modifiers & cmdKey )
  385.                 doCmdKey((char)(e->message & charCodeMask));
  386.             else
  387.                 SysBeep(10);
  388.             break;
  389.     }
  390. }
  391.  
  392.  
  393. /*
  394.  *  doGoodBye - respond to "goodbye kiss"
  395.  *
  396.  *  This is called by the system when the application quits while
  397.  *  the DA is still open.  We need to close our file, so we have 
  398.  *    requested a "goodbye kiss".
  399.  *
  400.  */
  401.  
  402. doGoodBye()
  403. {
  404.     Close_File(fileRef);
  405. }
  406.  
  407. /* error handling: */
  408.  
  409. ErrorStr(s)
  410. char *s;
  411. {
  412.     ParamText(s,"","","");
  413.     Alert( OwnedResourceID(ERROR_ALERT), 0L );
  414.     doUpdate();
  415. }
  416.  
  417. Error(err)
  418. {
  419.     Str255 s;
  420.     
  421.     NumToString(err,s);
  422.     ParamText("\pHexDump detected error, ID = ",s,"","");
  423.     Alert( OwnedResourceID(ERROR_ALERT), 0L);
  424.     doUpdate();
  425. }
  426.  
  427. No_Error(err) 
  428. {
  429.     if (err==noErr) return true;
  430.     Error(err); 
  431.     return false;
  432. }
  433.  
  434. /* utility routines: */
  435.  
  436. /* OwnedResourceID - Compute the resource ID of */
  437. /*    a resource owned by this DA.                */
  438.  
  439. OwnedResourceID(n)
  440. {
  441.     return( 0xC000 + ((~(dce->dCtlRefNum))<<5) + n );
  442. }
  443.  
  444. /* Get_Wait_Cursor -
  445.  *     Load the variable "wait" with the watch cursor.
  446.  *     Dispose the resource's copy in memory if it wasn't already there.
  447.  */
  448.  
  449. Get_Wait_Cursor()
  450. {
  451.     CursHandle     h;
  452.     Boolean     dispose;
  453.     
  454.     SetResLoad(false);
  455.     h = GetCursor(watchCursor);
  456.     dispose = (GetHandleSize((Handle)h) == 0);
  457.     SetResLoad(true);
  458.     BlockMove(*(h=GetCursor(watchCursor)), &wait, sizeof( Cursor ));
  459.     if (dispose) ReleaseResource((Handle)h);
  460. }
  461.  
  462.